package com.xg.mina;

import com.xg.mina.message.Constant;
import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

public class ShakeMessage {
    public static final Logger LOGGER = LoggerFactory.getLogger(ShakeMessage.class);
    private byte[] data;

    private byte[] c1 = null;
    private byte[] c1_digest = null;
    private byte[] c1_key = null;
    private byte[] c1_calc_digest = null;

    private byte[] s1 = null;
    private byte[] s1_digest = null;
    private byte[] s1_key = null;
    private byte[] s1_calc_digest = null;

    private byte[] c2 = null;
    private byte[] c2_digest = null;
    private byte[] c2_key = null;
    private byte[] c2_calc_digest = null;

    public IoBuffer createC0C1(byte[] randomByte) {
        return createBuffer(randomByte);
    }

    public IoBuffer createC0() {
        IoBuffer c0 = IoBuffer.allocate(1);
        c0.put(Constant.version);
        return c0;
    }

    public IoBuffer createC0C1() {
        byte[] randomByte = Utils.createRandomByte(Constant.hand_shake_size);

        int time = 0;
        randomByte[0] = (byte) (time >>> 24);
        randomByte[1] = (byte) (time >>> 16);
        randomByte[2] = (byte) (time >>> 8);
        randomByte[3] = (byte) time;

        //客户端flash 版本
        randomByte[4] = Constant.client_version[0];
        randomByte[5] = Constant.client_version[1];
        randomByte[6] = Constant.client_version[2];
        randomByte[7] = Constant.client_version[3];

        return createBuffer(randomByte);
    }

    private IoBuffer createBuffer(byte[] c1) {
        IoBuffer c0c1 = IoBuffer.allocate(Constant.hand_shake_size + 1);
        c0c1.setAutoShrink(true);
        c0c1.setAutoExpand(true);

        int c1Offest = Utils.calcOffset(c1, 0);
        byte[] c1_join = Utils.joinData(c1, c1Offest);
        byte[] c1_key = Arrays.copyOfRange(Constant.GENUINE_FP_KEY, 0, 30);

        this.c1_key = c1_key;

        byte[] c1_digest = Utils.calcSha256(c1_join, c1_key);
        this.c1_digest = c1_digest;
        this.c1_calc_digest = this.c1_key;

        System.arraycopy(c1_digest, 0, c1, c1Offest, Constant.digest_length);
        this.c1 = c1;

        IoBuffer c0 = createC0();
        c0c1.put(c0.array());
        c0c1.put(c1);

        this.data = c1;
        return c0c1;
    }

    public IoBuffer createC2(byte[] s1, byte[] c2) {
        IoBuffer buffer = IoBuffer.allocate(Constant.hand_shake_size);
        buffer.setAutoShrink(true);
        buffer.setAutoExpand(true);
        //c2的构造方法和s2相同
        //只不过它是用s2中的digest作为hmac-sha256的key

        int digestPosServer = Utils.calcOffset(s1, 0);
        System.out.println("s1 offset："+ digestPosServer);

        byte[] incomingDigest = new byte[Constant.digest_length];
        System.arraycopy(s1, digestPosServer, incomingDigest, 0, Constant.digest_length);
        this.s1_calc_digest = incomingDigest;

        byte[] digestResp = Utils.calcSha256(incomingDigest, Constant.GENUINE_FP_KEY);
        this.c2_calc_digest = digestResp;

        byte[] bytes = Arrays.copyOfRange(c2, 0, Constant.hand_shake_size - Constant.digest_length);
        byte[] digest = Utils.calcSha256(bytes, digestResp);
        this.c2_digest = digest;

        this.c2 = c2;
        this.data = this.c2;
        buffer.put(bytes);
        buffer.put(digest);

        return buffer;
    }

    public IoBuffer createC2(byte[] s1) {
        byte[] c2 = Utils.createRandomByte(Constant.hand_shake_size);
        return createC2(s1, c2);
    }

    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    public byte[] getC1() {
        return c1;
    }

    public void setC1(byte[] c1) {
        this.c1 = c1;
    }

    public byte[] getC1_digest() {
        return c1_digest;
    }

    public void setC1_digest(byte[] c1_digest) {
        this.c1_digest = c1_digest;
    }

    public byte[] getC1_key() {
        return c1_key;
    }

    public void setC1_key(byte[] c1_key) {
        this.c1_key = c1_key;
    }

    public byte[] getC1_calc_digest() {
        return c1_calc_digest;
    }

    public void setC1_calc_digest(byte[] c1_calc_digest) {
        this.c1_calc_digest = c1_calc_digest;
    }

    public byte[] getC2() {
        return c2;
    }

    public void setC2(byte[] c2) {
        this.c2 = c2;
    }

    public byte[] getC2_digest() {
        return c2_digest;
    }

    public void setC2_digest(byte[] c2_digest) {
        this.c2_digest = c2_digest;
    }

    public byte[] getC2_key() {
        return c2_key;
    }

    public void setC2_key(byte[] c2_key) {
        this.c2_key = c2_key;
    }

    public byte[] getC2_calc_digest() {
        return c2_calc_digest;
    }

    public void setC2_calc_digest(byte[] c2_calc_digest) {
        this.c2_calc_digest = c2_calc_digest;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("");
        if (data == null) sb.append("null");
        else {
            sb.append('[');
            for (int i = 0; i < data.length; ++i)
                sb.append(i == 0 ? "" : ", ").append(data[i]);
            sb.append(']');
        }
        return sb.toString();
    }
}
